//////////////////////////////////////////////////////////////////////////
/// Copyright (c) 2011, Sidorenko 'PC' Alexander                       ///
/// mailto: sidorenko /*dot*/ alexander (at) gmail [dot] com           ///
/// This file is a part of the Radiating Gas Dynamics project          ///
//////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "RGD.h"
#include "Timeline.h"
#include "Problem/Problem.h"

// CTimeline dialog

IMPLEMENT_DYNAMIC(CTimeline, CDialog)

CTimeline::CTimeline(CWnd* pParent /*=NULL*/)
	: CDialog(CTimeline::IDD, pParent)
	, m_pListener(NULL)
	, m_numTimesteps(101)
	, m_playbackTime(3)
	, m_step(0)
	, m_looped(TRUE)
	, m_bPlaying(false)
	, m_prevTick(0)
	, m_floatStep(0)
	, m_pCurProblem(NULL)
	, m_plotType(0)
{
}

CTimeline::~CTimeline()
{
}

void CTimeline::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Slider(pDX, IDC_TIMELINE, m_step);
	DDX_Check(pDX, IDC_LOOPED, m_looped);
	DDX_CBIndex(pDX, IDC_PLOT_TYPE, m_plotType);
}


BEGIN_MESSAGE_MAP(CTimeline, CDialog)
	ON_WM_SIZE()
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_PLAY, &CTimeline::OnBnClickedPlay)
	ON_BN_CLICKED(IDC_LOOPED, &CTimeline::OnBnClickedLooped)
	ON_WM_HSCROLL()
	ON_CBN_SELCHANGE(IDC_PLOT_TYPE, &CTimeline::OnCbnSelchangePlotType)
END_MESSAGE_MAP()


// CTimeline message handlers
void CTimeline::setProblem(Problem *pr)
{
	m_pCurProblem = pr;
	CComboBox* pBox = static_cast<CComboBox*>(GetDlgItem(IDC_PLOT_TYPE));
	_ASSERT(pBox != NULL);
	pBox->ResetContent();
	if (m_pCurProblem != NULL)
	{
		SetNumTimesteps(m_pCurProblem->getNumSteps());
		unsigned int numTimesteps = m_pCurProblem->getNumSteps();
		SetPlaybackTime(gdScalar(numTimesteps) / gdScalar(120.0));

		for (unsigned int i = 0; i < m_pCurProblem->getNumPlotTypes(); ++i)
		{
			CString str(m_pCurProblem->getPlotTypeName(i).c_str());
			pBox->AddString(str);
		}
		m_plotType = 0;
		UpdateData(false);
		GetDlgItem(IDC_PLAY)->EnableWindow(true);
		GetDlgItem(IDC_SLIDER1)->EnableWindow(true);
		GetDlgItem(IDC_LOOPED)->EnableWindow(true);
		GetDlgItem(IDC_PLOT_TYPE)->EnableWindow(true);
		SetCutStep(0);
	}
	else
	{
		GetDlgItem(IDC_PLAY)->EnableWindow(false);
		GetDlgItem(IDC_SLIDER1)->EnableWindow(false);
		GetDlgItem(IDC_LOOPED)->EnableWindow(false);
		GetDlgItem(IDC_PLOT_TYPE)->EnableWindow(false);
		GetDlgItem(IDC_PLOT_INFO)->SetWindowText(_T("Please, start new simulation"));
		SetCutStep(0);
	}
}

void CTimeline::PlotCurrentSolution(CDC& dc, const CRect& rect, const CColorBar& color)
{
	if (m_pCurProblem != NULL)
	{
		m_pCurProblem->plotSolution(dc, rect, color, getCurPlotStep(), m_plotType);
	}
}

void CTimeline::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);

	if (GetDlgItem(IDC_TIMELINE) != NULL)
	{
		ResizeTimeline();
	}
}

//////////////////////////////////////////////////////////////////////////
void CTimeline::ResizeTimeline()
{
	CWnd* pTimeline = GetDlgItem(IDC_TIMELINE);
	_ASSERT(pTimeline != NULL);
	CRect cliRect;
	GetClientRect(cliRect);
	CRect timeRect;
	pTimeline->GetWindowRect(timeRect);
	ScreenToClient(timeRect);
	timeRect.right = cliRect.right;
	pTimeline->MoveWindow(timeRect, true);
}

//////////////////////////////////////////////////////////////////////////
void CTimeline::SetNumTimesteps(unsigned int numSteps)
{
	m_numTimesteps = numSteps;
	CSliderCtrl* pCtrl = static_cast<CSliderCtrl*>(GetDlgItem(IDC_TIMELINE));
	_ASSERT(pCtrl != NULL);
	pCtrl->SetRangeMax(numSteps - 1);
	pCtrl->SetLineSize(1);
	pCtrl->SetTicFreq(1);
	Pause();
}

//////////////////////////////////////////////////////////////////////////
void CTimeline::SetPlaybackTime(gdScalar time)
{
	m_playbackTime = time;
}

void CTimeline::OnTimer(UINT_PTR nIDEvent)
{
	unsigned int curTickCount = GetTickCount();
	gdScalar dt = gdScalar(curTickCount - m_prevTick) / gdScalar(1000);
	m_prevTick = curTickCount;
	m_floatStep += dt * gdScalar(m_numTimesteps - 1) / m_playbackTime;
	if (m_floatStep > gdScalar(m_numTimesteps - 1))
	{
		if (m_looped)
		{
			m_floatStep -= gdScalar(m_numTimesteps - 1);
		}
		else
		{
			m_floatStep = gdScalar(m_numTimesteps - 1);
			Pause();
		}
	}
	SetCutStep((unsigned int)m_floatStep);

	CDialog::OnTimer(nIDEvent);
}

//////////////////////////////////////////////////////////////////////////
void CTimeline::Pause()
{
	if (!m_bPlaying)
	{
		return;
	}

	CWnd *pWnd = GetDlgItem(IDC_PLAY);
	_ASSERT(pWnd != NULL);
	pWnd->SetWindowText(_T("Play"));
	KillTimer(0);

	m_bPlaying = false;
}

//////////////////////////////////////////////////////////////////////////
void CTimeline::Play()
{
	if (m_bPlaying)
	{
		return;
	}

	CWnd *pWnd = GetDlgItem(IDC_PLAY);
	_ASSERT(pWnd != NULL);
	pWnd->SetWindowText(_T("Pause"));

	SetTimer(0, 1, NULL);
	m_prevTick = GetTickCount();

	if (m_step == m_numTimesteps - 1)
	{
		m_step = 0;
		m_floatStep = 0.0f;
		UpdateData(false);
	}

	m_bPlaying = true;
}

unsigned int CTimeline::getCurPlotStep() const
{
	//gdScalar factor = m_floatStep / gdScalar(m_numTimesteps - 1);
	//_ASSERT(m_pCurProblem != NULL);
	//return (unsigned int)(factor * gdScalar(m_pCurProblem->getNumSteps() - 1));
	return m_step;
}

//////////////////////////////////////////////////////////////////////////
void CTimeline::SetCutStep(unsigned int step)
{
	{
		m_step = step;
		m_floatStep = gdScalar(step);
		if (m_pListener != NULL)
		{
			m_pListener->OnTimeChanged(m_floatStep / gdScalar(m_numTimesteps - 1));
		}
		UpdateData(false);
		if (m_pCurProblem != NULL)
		{
			// Update statistics
			TCHAR buf[1024];
			gdScalar curTime, totalTime;
			unsigned int curStep = getCurPlotStep();
			curTime = m_pCurProblem->getTime(curStep);
			totalTime = m_pCurProblem->getTime(m_pCurProblem->getNumSteps() - 1);
			_stprintf(buf, _T("Model Time: %f/%f; Timestep: %d/%d"), curTime, totalTime, curStep + 1, m_pCurProblem->getNumSteps());
			GetDlgItem(IDC_PLOT_INFO)->SetWindowText(buf);
		}
	}
}

void CTimeline::OnBnClickedPlay()
{
	if (m_bPlaying)
	{
		Pause();
	}
	else
	{
		Play();
	}
}

void CTimeline::OnBnClickedLooped()
{
	UpdateData(TRUE);
}

void CTimeline::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	Pause();

	UpdateData(TRUE);
	SetCutStep(m_step);

	CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CTimeline::OnCbnSelchangePlotType()
{
	UpdateData(TRUE);
	if (m_pListener != NULL)
	{
		m_pListener->OnPlotTypeChanged();
	}
}
